/**
 *   Copyright (C) Sangfor Corporation. All rights reserved.

 *   \file     socket_widget.h
 *   \author   RainVan(Yunfeng.Xiao)
 *   \date     Sep 2011
 *   \version  1.0.0
 *   \brief    Interface of socket widget
 */

#ifndef __SOCKET_WIDGET_H__
#define __SOCKET_WIDGET_H__

#include "ip_address.h"
#include <assert.h>
#include <unistd.h>
#include <errno.h>
#include <sys/un.h>

/*! assert of socket
 */
#define SOCKET_ASSERT  assert

#if defined(__cplusplus)
extern "C" {
#endif

    /*! socket type
     */
    typedef int socket_t;

    /**
     *  \brief          Set a socket as block mode (with timeout)
     *  \param fd       The descriptor of socket
     *  \param sec      The seconds of send/recv timeout 
     *  \param usec     The microseconds of send/recv timeout 
     *  \return         0 indicates success, -1 indicates failure.
     */
    int socket_set_block(socket_t fd, long sec, long usec);

    /**
     *  \brief          Set a socket as non-block mode
     *  \param fd       The descriptor of socket
     *  \return         0 indicates success, -1 indicates failure.
     */
    int socket_set_nonblock(socket_t fd);

    /**
     *  \brief          Create a UDP server non-block socket
     *  \param addr     The IP address bound (can't be null)
     *  \param port     The port bound (0 indicates any port)
     *  \param reuse    The boolean indicating if it can reuse the IP address 
     *  \return         The descriptor of socket, -1 indicates failure.
     */
    socket_t socket_udp_server(
        const ip_address_t *addr, uint16_t port, int reuse
        );

    /**
     *  \brief          Create a UDP client socket
     *  \param addr     The IP address bound (can't be null)
     *  \param port     The port bound (0 indicates any port)
     *  \return         The descriptor of socket, -1 indicates failure.
     */
    socket_t socket_udp_client(const ip_address_t *addr, uint16_t port);

    /**
     *  \brief          Create a TCP server non-block socket
     *  \param addr     The IP address bound (can't be null)
     *  \param port     The port bound (0 indicates any port)
     *  \param reuse    The boolean indicating if it can reuse the IP address 
     *  \return         The descriptor of socket, -1 indicates failure.
     */
    socket_t socket_tcp_server(
        const ip_address_t *addr, uint16_t port, int reuse
        );

    /**
     *  \brief          Create a TCP client socket
     *  \param addr     The IP address bound (can't be null)
     *  \param port     The port bound (0 indicates any port)
     *  \return         The descriptor of socket, -1 indicates failure.
     */
    socket_t socket_tcp_client(const ip_address_t *addr, uint16_t port);

    /**
     *  \brief          Accept a new connection on a socket
     *  \param fd       The descriptor of socket (listener)
     *  \param addr     The pointer for receiving peer address (can be null)
     *  \param port     The pointer for receiving peer port (can be null)
     *  \return         The descriptor of new socket, -1 indicates failure.
     */
    socket_t socket_accept(socket_t fd, ip_address_t *addr, uint16_t *port);

    /**
     *  \brief          Accept a new connection on a socket
     *  \param fd       The descriptor of socket (listener)
     *  \param addr     The pointer for receiving peer address (can be null)
     *  \param port     The pointer for receiving peer port (can be null)
     *  \param n        The retries when EAGAIN error occurred
     *  \return         The descriptor of new socket, -1 indicates failure.
     */
    socket_t socket_accept_n(
        socket_t fd, ip_address_t *addr, uint16_t *port, size_t n
        );

    /**
     *  \brief          Bind a name to a socket
     *  \param fd       The descriptor of socket
     *  \param addr     The IP address bound (can't be null)
     *  \param port     The port bound (0 indicates any port)
     *  \return         0 indicates success, -1 indicates failure.
     */
    int socket_bind(socket_t fd, const ip_address_t *addr, uint16_t port);

    /**
     *  \brief          Connect a socket
     *  \param fd       The descriptor of socket
     *  \param addr     The peer address (can't be null)
     *  \param port     The peer port (can't be zero)
     *  \return         0 indicates success, -1 indicates failure.
     */
    int socket_connect(socket_t fd, const ip_address_t *addr, uint16_t port);

    /**
     *  \brief          Connect a socket
     *  \param fd       The descriptor of socket
     *  \param addr     The peer address (can't be null)
     *  \param port     The peer port (can't be zero)
     *  \param n        The retries when EAGAIN error occurred
     *  \return         0 indicates success, -1 indicates failure.
     */
    int socket_connect_n(
        socket_t fd, const ip_address_t *addr, uint16_t port, size_t n
        );

    /**
     *  \brief          Receive data from a socket safely (UDP)
     *  \param fd       The descriptor of socket
     *  \param buf      The pointer of buffer
     *  \param len      The length of receiving
     *  \param addr     The pointer for receiving peer address (can be null)
     *  \param port     The pointer for receiving peer port (can be null)
     *  \return         The bytes actually receive, -1 indicates failure.
     */
    ssize_t socket_recvfrom(
        socket_t fd, void *buf, size_t len, ip_address_t *addr, uint16_t *port
        );

    /**
     *  \brief          Send data to a socket safely (UDP)
     *  \param fd       The descriptor of socket
     *  \param buf      The pointer of buffer
     *  \param len      The length of sending
     *  \param addr     The peer address (can't be null)
     *  \param port     The peer port (can't be zero)
     *  \return         The bytes actually send, -1 indicates failure.
     */
    ssize_t socket_sendto(
        socket_t fd, const void *buf, size_t len, 
        const ip_address_t *addr, uint16_t port
        );

    /**
     *  \brief          Receive data from a socket safely (UDP)
     *  \param fd       The descriptor of socket
     *  \param buf      The pointer of buffer
     *  \param len      The length of receiving
     *  \param addr     The pointer for receiving peer address (can be null)
     *  \param port     The pointer for receiving peer port (can be null)
     *  \param n        The retries when EAGAIN error occurred
     *  \return         The bytes actually receive, -1 indicates failure.
     */
    ssize_t socket_recvfrom_n(
        socket_t fd, void *buf, size_t len, 
        ip_address_t *addr, uint16_t *port, size_t n
        );

    /**
     *  \brief          Send data to a socket safely (UDP)
     *  \param fd       The descriptor of socket
     *  \param buf      The pointer of buffer
     *  \param len      The length of sending
     *  \param addr     The peer address (can't be null)
     *  \param port     The peer port (can't be zero)
     *  \param n        The retries when EAGAIN error occurred
     *  \return         The bytes actually send, -1 indicates failure.
     */
    ssize_t socket_sendto_n(
        socket_t fd, const void *buf, size_t len, 
        const ip_address_t *addr, uint16_t port, size_t n
        );

    /**
     *  \brief          Get the socket name
     *  \param fd       The descriptor of socket
     *  \param addr     The pointer for receiving address (can be null)
     *  \param port     The pointer for receiving port (can be null)
     *  \return         0 indicates success, -1 indicates failure.
     */
    int socket_get_sockname(socket_t fd, ip_address_t *addr, uint16_t *port);

    /**
     *  \brief          Get the name of the peer socket
     *  \param fd       The descriptor of socket
     *  \param addr     The pointer for receiving address (can be null)
     *  \param port     The pointer for receiving port (can be null)
     *  \return         0 indicates success, -1 indicates failure.
     */
    int socket_get_peername(socket_t fd, ip_address_t *addr, uint16_t *port);

    /**
     *  \brief          Get the family of socket
     *  \param fd       The descriptor of socket
     *  \return         The value of family, 0 indicates unspecified type.
     */
    uint16_t socket_get_family(socket_t fd);

    /**
     *  \brief          Listen for socket connections with MAX queues
     *  \param fd       The descriptor of socket
     *  \return         0 indicates success, -1 indicates failure.
     */
    int socket_listen(socket_t fd);

    /**
     *  \brief          Reset and close a socket
     *  \param fd       The descriptor of socket
     *  \return         0 indicates success, -1 indicates failure.
     */
    int socket_reset(socket_t fd);

    /**
     *  \brief          Close a socket safely
     *  \param fd       The descriptor of socket
     *  \return         0 indicates success, -1 indicates failure.
     */
    int socket_close(socket_t fd);

    /**
     *  \brief          Shutdown socket all operations (send and receive)
     *  \param fd       The descriptor of socket
     *  \return         0 indicates success, -1 indicates failure.
     */
    int socket_shutdown(socket_t fd);

    /**
     *  \brief          Read data from a socket safely
     *  \param fd       The descriptor of socket
     *  \param buf      The pointer of buffer
     *  \param len      The length of reading
     *  \return         The bytes actually read, -1 indicates failure.
     */
    ssize_t socket_read(socket_t fd, void *buf, size_t len);

    /**
     *  \brief          Write data to a socket safely
     *  \param fd       The descriptor of socket
     *  \param buf      The pointer of buffer
     *  \param len      The length of writing
     *  \return         The bytes actually write, -1 indicates failure.
     */
    ssize_t socket_write(socket_t fd, const void *buf, size_t len);

    /**
     *  \brief          Read data from a socket fully
     *  \param fd       The descriptor of socket
     *  \param buf      The pointer of buffer
     *  \param len      The length of reading
     *  \return         The bytes actually read, -1 indicates failure.
     */
    ssize_t socket_read_n(socket_t fd, void *buf, size_t len);

    /**
     *  \brief          Write data to a socket fully
     *  \param fd       The descriptor of socket
     *  \param buf      The pointer of buffer
     *  \param len      The length of writing
     *  \return         The bytes actually write, -1 indicates failure.
     */
    ssize_t socket_write_n(socket_t fd, const void *buf, size_t len);

    /**
     *  \brief          Create a Unix UDP client socket
     *  \param path     The string of path bound (can be null)
     *  \return         The descriptor of socket, -1 indicates failure.
     */
    socket_t socket_unix_udp_client(const char *path);

    /**
     *  \brief          Create a Unix UDP server non-block socket
     *  \param path     The string of path bound (can't be null)
     *  \param reuse    The boolean indicating if it can reuse the address 
     *  \return         The descriptor of socket, -1 indicates failure.
     */
    socket_t socket_unix_udp_server(const char *path, int reuse);

    /**
     *  \brief          Create a Unix TCP client socket
     *  \param path     The string of path bound (can be null)
     *  \return         The descriptor of socket, -1 indicates failure.
     */
    socket_t socket_unix_tcp_client(const char *path);

    /**
     *  \brief          Create a Unix TCP server non-block socket
     *  \param path     The string of path bound (can't be null)
     *  \param reuse    The boolean indicating if it can reuse the address 
     *  \return         The descriptor of socket, -1 indicates failure.
     */
    socket_t socket_unix_tcp_server(const char *path, int reuse);

    /**
     *  \brief          Accept a new connection on a Unix socket
     *  \param fd       The descriptor of socket (listener)
     *  \param path     The buffer for receiving path (can be null)
     *  \param size     The size of buffer (can be zero)
     *  \return         The descriptor of new socket, -1 indicates failure.
     */
    socket_t socket_unix_accept(socket_t fd, char *path, size_t size);

    /**
     *  \brief          Accept a new connection on a Unix socket
     *  \param fd       The descriptor of socket (listener)
     *  \param path     The buffer for receiving path (can be null)
     *  \param size     The size of buffer (can be zero)
     *  \param n        The retries when EAGAIN error occurred
     *  \return         The descriptor of new socket, -1 indicates failure.
     */
    socket_t socket_unix_accept_n(
        socket_t fd, char *path, size_t size, size_t n
        );

    /**
     *  \brief          Bind a path to a Unix socket
     *  \param fd       The descriptor of socket
     *  \param path     The string of path bound (can't be null)
     *  \return         0 indicates success, -1 indicates failure.
     */
    int socket_unix_bind(socket_t fd, const char *path);

    /**
     *  \brief          Connect a Unix socket
     *  \param fd       The descriptor of socket
     *  \param path     The path of peer (can't be null)
     *  \return         0 indicates success, -1 indicates failure.
     */
    int socket_unix_connect(socket_t fd, const char *path);
    /**
     *  \brief          Connect a Unix socket and have timeout 
     *  \param fd       The descriptor of socket
     *  \param path     The path of peer (can't be null)
     *  \second     	The time limit	
     *  \return         0 indicates success, -1 indicates failure.
     */
    int socket_unix_connect_timeout(socket_t fd, const char *path, int second);

    /**
     *  \brief          Connect a Unix socket
     *  \param fd       The descriptor of socket
     *  \param path     The path of peer (can't be null)
     *  \param n        The retries when EAGAIN error occurred
     *  \return         0 indicates success, -1 indicates failure.
     */
    int socket_unix_connect_n(socket_t fd, const char *path, size_t n);

    /**
     *  \brief          Receive data from a socket safely (Packet)
     *  \param fd       The descriptor of socket
     *  \param buf      The pointer of buffer
     *  \param len      The length of receiving
     *  \param path     The buffer for receiving path (can be null)
     *  \param size     The size of buffer (can be zero)
     *  \return         The bytes actually receive, -1 indicates failure.
     */
    ssize_t socket_unix_recvfrom(
        socket_t fd, void *buf, size_t len, char *path, size_t size
        );

    /**
     *  \brief          Receive data from a socket safely (Packet)
     *  \param fd       The descriptor of socket
     *  \param buf      The pointer of buffer
     *  \param len      The length of receiving
     *  \param path     The buffer for receiving path (can be null)
     *  \param size     The size of buffer (can be zero)
     *  \param n        The retries when EAGAIN error occurred
     *  \return         The bytes actually receive, -1 indicates failure.
     */
    ssize_t socket_unix_recvfrom_n(
        socket_t fd, void *buf, size_t len, char *path, size_t size, size_t n
        );

    /**
     *  \brief          Send data to a Unix socket safely (Packet)
     *  \param fd       The descriptor of socket
     *  \param buf      The pointer of buffer
     *  \param len      The length of sending
     *  \param path     The path of peer (can't be null)
     *  \return         The bytes actually send, -1 indicates failure.
     */
    ssize_t socket_unix_sendto(
        socket_t fd, const void *buf, size_t len, const char *path
        );

    /**
     *  \brief          Send data to a Unix socket safely (Packet)
     *  \param fd       The descriptor of socket
     *  \param buf      The pointer of buffer
     *  \param len      The length of sending
     *  \param path     The path of peer (can't be null)
     *  \param n        The retries when EAGAIN error occurred
     *  \return         The bytes actually send, -1 indicates failure.
     */
    ssize_t socket_unix_sendto_n(
        socket_t fd, const void *buf, size_t len, const char *path, size_t n
        );

    /**
     *  \brief          Get the Unix socket name
     *  \param fd       The descriptor of socket
     *  \param path     The buffer for receiving path (can't be null)
     *  \param size     The size of buffer (can't be zero)
     *  \return         0 indicates success, -1 indicates failure.
     */
    int socket_unix_get_sockname(socket_t fd, char *path, size_t size);

    /**
     *  \brief          Get the name of the peer Unix socket
     *  \param fd       The descriptor of socket
     *  \param path     The buffer for receiving path (can't be null)
     *  \param size     The size of buffer (can't be zero)
     *  \return         0 indicates success, -1 indicates failure.
     */
    int socket_unix_get_peername(socket_t fd, char *path, size_t size);


#if defined(__cplusplus)
} /* extern "C" */
#endif

#endif /*__SOCKET_WIDGET_H__*/
